/**
 * 安卓白金英雄坛制作组 <br>
 * 文件名：BmobOperation.java <br>
 * 创建时间：2014-9-12 上午9:57:06 <br>
 * 所属项目：GmudEX <br>
 * @author 12548 <br>
 */
package lostland.general.bmob;

import android.content.Context;

import java.util.List;

import cn.bmob.v3.BmobObject;
import cn.bmob.v3.BmobQuery;
import cn.bmob.v3.listener.DeleteListener;
import cn.bmob.v3.listener.FindListener;
import cn.bmob.v3.listener.GetListener;
import cn.bmob.v3.listener.SaveListener;
import cn.bmob.v3.listener.UpdateListener;

/**
 * 类名：BmobOperation <br>
 * 说明：对Bmob操作进行的封装。
 *
 * @author 12548
 */
public class BmobOperation<T extends BmobObject> {

	protected T object = null;
	protected BmobQuery<T> query = null;
	protected List<T> data = null;

	protected int errCode;
	protected String errMsg;

	protected String objectID;

	public int tag = -1;
	protected Context game;

	protected OnSuccessListener<T> onSuccessListener = null;
	protected OnEmptyListener<T> onEmptyListener = null;
	protected OnFailedListener<T> onFailedListener = null;

	public void saveOrUpdate(T obj, BmobQuery<T> q) {

		this.object = obj;
		this.query = q;

		q.findObjects(game, new FindListener<T>() {

			@Override
			public void onError(int arg0, String arg1) {
				BmobOperation.this.errCode = arg0;
				BmobOperation.this.errMsg = arg1;

				if (onFailedListener != null)
					onFailedListener.onFailed(BmobOperation.this);
			}

			@Override
			public void onSuccess(List<T> arg0) {
				BmobOperation.this.data = arg0;
				if (arg0.isEmpty()) {
					BmobOperation.this.object.save(game, saveListener);
				} else {
					BmobOperation.this.object.update(game, arg0.get(0).getObjectId(), updateListener);
				}
			}
		});
	}

	public void save(T obj) {
		this.object = obj;
		obj.save(game, saveListener);
	}

	public void update(T obj) {
		this.object = obj;
		obj.update(game, updateListener);
	}

	public void update(T obj, String objID) {
		this.object = obj;
		this.objectID = objID;

		obj.update(game, objID, updateListener);
	}

	public void get(String objID) {
		this.objectID = objID;
		this.query = new BmobQuery<>();
		query.getObject(game, objID, getListener);
	}

	public void delete(T obj) {
		this.object = obj;
//		obj.delete(game, this);
	}

	public void find(BmobQuery<T> q) {
		this.query = q;
		q.findObjects(game, findListener);
	}

	public void findAndDeleteOne(BmobQuery<T> q) {
		this.query = q;

		q.findObjects(game, new FindListener<T>() {

			@Override
			public void onError(int arg0, String arg1) {
				BmobOperation.this.errCode = arg0;
				BmobOperation.this.errMsg = arg1;

				if (onFailedListener != null)
					onFailedListener.onFailed(BmobOperation.this);
			}

			@Override
			public void onSuccess(List<T> arg0) {
				data = arg0;
				if (arg0.isEmpty()) {
					if (onEmptyListener != null) {
						onEmptyListener.onEmpty(BmobOperation.this);
					}
				} else {
					delete(arg0.get(0));
				}
			}

		});
	}

	private static final class PackedFindListener<T extends BmobObject> extends FindListener<T> {
		private BmobOperation<T> bo;

		private PackedFindListener(BmobOperation<T> bo) {
			this.bo = bo;
		}

		/* （非 Javadoc）
		 * @see cn.bmob.v3.listener.FindListener#onError(int, java.lang.String)
		 */
		@Override
		public void onError(int arg0, String arg1) {
			bo.errCode = arg0;
			bo.errMsg = arg1;

			if (bo.onFailedListener != null)
				bo.onFailedListener.onFailed(bo);
		}

		/* （非 Javadoc）
		 * @see cn.bmob.v3.listener.FindListener#onSuccess(java.util.List)
		 */
		@Override
		public void onSuccess(List<T> arg0) {
			bo.data = arg0;
			if (arg0.isEmpty() && bo.onEmptyListener != null) {
				bo.onEmptyListener.onEmpty(bo);
			} else if (bo.onSuccessListener != null)
				bo.onSuccessListener.onSuccess(bo);
		}

	}

	private static final class PackedDeleteListener<T extends BmobObject> extends DeleteListener {

		private BmobOperation<T> bo;

		private PackedDeleteListener(BmobOperation<T> bo) {
			this.bo = bo;
		}

		/* （非 Javadoc）
		 * @see cn.bmob.v3.listener.GetListener#onFailure(int, java.lang.String)
		 */
		@Override
		public void onFailure(int arg0, String arg1) {
			bo.errCode = arg0;
			bo.errMsg = arg1;

			if (bo.onFailedListener != null)
				bo.onFailedListener.onFailed(bo);
		}

		/* （非 Javadoc）
		 * @see cn.bmob.v3.listener.GetListener#onSuccess(java.lang.Object)
		 */
		@Override
		public void onSuccess() {
			if (bo.onSuccessListener != null)
				bo.onSuccessListener.onSuccess(bo);
		}

	}

	private static final class PackedGetListener<T extends BmobObject> extends GetListener<T> {
		private BmobOperation<T> bo;

		private PackedGetListener(BmobOperation<T> bo) {
			this.bo = bo;
		}

		/* （非 Javadoc）
		 * @see cn.bmob.v3.listener.GetListener#onFailure(int, java.lang.String)
		 */
		@Override
		public void onFailure(int arg0, String arg1) {
			bo.errCode = arg0;
			bo.errMsg = arg1;

			if (bo.onFailedListener != null)
				bo.onFailedListener.onFailed(bo);
		}

		/* （非 Javadoc）
		 * @see cn.bmob.v3.listener.GetListener#onSuccess(java.lang.Object)
		 */
		@Override
		public void onSuccess(T arg0) {
			bo.object = arg0;
			if (bo.onSuccessListener != null)
				bo.onSuccessListener.onSuccess(bo);
		}

	}

	private static final class PackedUpdateListener<T extends BmobObject> extends UpdateListener {

		private BmobOperation<T> bo;

		private PackedUpdateListener(BmobOperation<T> bo) {
			this.bo = bo;
		}


		/* （非 Javadoc）
		 * @see cn.bmob.v3.listener.UpdateListener#onFailure(int, java.lang.String)
		 */
		@Override
		public void onFailure(int arg0, String arg1) {
			bo.errCode = arg0;
			bo.errMsg = arg1;

			if (bo.onFailedListener != null)
				bo.onFailedListener.onFailed(bo);
		}

		/* （非 Javadoc）
		 * @see cn.bmob.v3.listener.UpdateListener#onSuccess()
		 */
		@Override
		public void onSuccess() {
			if (bo.onSuccessListener != null)
				bo.onSuccessListener.onSuccess(bo);
		}

	}

	private static final class PackedSaveListener<T extends BmobObject> extends SaveListener {

		/**
		 * @param bo
		 */
		private PackedSaveListener(BmobOperation<T> bo) {
			this.bo = bo;
		}

		private BmobOperation<T> bo;

		/* （非 Javadoc）
		 * @see cn.bmob.v3.listener.SaveListener#onFailure(int, java.lang.String)
		 */
		@Override
		public void onFailure(int arg0, String arg1) {
			bo.errCode = arg0;
			bo.errMsg = arg1;

			if (bo.onFailedListener != null)
				bo.onFailedListener.onFailed(bo);
		}

		/* （非 Javadoc）
		 * @see cn.bmob.v3.listener.SaveListener#onSuccess()
		 */
		@Override
		public void onSuccess() {
			if (bo.onSuccessListener != null)
				bo.onSuccessListener.onSuccess(bo);
		}

	}

	PackedSaveListener<T> saveListener = new PackedSaveListener<>(this);
	PackedUpdateListener<T> updateListener = new PackedUpdateListener<>(this);
	PackedGetListener<T> getListener = new PackedGetListener<>(this);
	PackedDeleteListener<T> deleteListener = new PackedDeleteListener<>(this);
	PackedFindListener<T> findListener = new PackedFindListener<>(this);

	/**
	 *
	 */
	public BmobOperation(Context game) {
		this.game = game;
	}

	/**
	 *
	 */
	public BmobOperation(Context game, int tag) {
		this.game = game;
		this.tag = tag;
	}

	public interface OnSuccessListener<T extends BmobObject> {
		void onSuccess(BmobOperation<T> sender);
	}

	public interface OnEmptyListener<T extends BmobObject> {
		void onEmpty(BmobOperation<T> sender);
	}

	public interface OnFailedListener<T extends BmobObject> {
		void onFailed(BmobOperation<T> sender);
	}

	/**
	 * @return onSuccessListener
	 */
	public OnSuccessListener<T> getOnSuccessListener() {
		return onSuccessListener;
	}

	/**
	 * @param onSuccessListener 要设置的 onSuccessListener
	 */
	public void setOnSuccessListener(OnSuccessListener<T> onSuccessListener) {
		this.onSuccessListener = onSuccessListener;
	}

	/**
	 * @return onEmptyListener
	 */
	public OnEmptyListener<T> getOnEmptyListener() {
		return onEmptyListener;
	}

	/**
	 * @param onEmptyListener 要设置的 onEmptyListener
	 */
	public void setOnEmptyListener(OnEmptyListener<T> onEmptyListener) {
		this.onEmptyListener = onEmptyListener;
	}

	/**
	 * @return onFailedListener
	 */
	public OnFailedListener<T> getOnFailedListener() {
		return onFailedListener;
	}

	/**
	 * @param onFailedListener 要设置的 onFailedListener
	 */
	public void setOnFailedListener(OnFailedListener<T> onFailedListener) {
		this.onFailedListener = onFailedListener;
	}

	/**
	 * @return object
	 */
	public T getObject() {
		return object;
	}

	/**
	 * @return query
	 */
	public BmobQuery<T> getQuery() {
		return query;
	}

	/**
	 * @return data
	 */
	public List<T> getData() {
		return data;
	}

	/**
	 * @return errCode
	 */
	public int getErrCode() {
		return errCode;
	}

	/**
	 * @return errMsg
	 */
	public String getErrMsg() {
		return errMsg;
	}

	/**
	 * @return objectID
	 */
	public String getObjectID() {
		return objectID;
	}
}
